package com.bugsnag.ohos;

import java.util.Map;
import java.util.Set;

/**
 * MetadataState
 *
 * @since 2021-07-02
 */
public class MetadataState extends BaseObservable implements MetadataAware {
    private Metadata metadata;

    /**
     * constructor
     */
    public MetadataState() {
        this(new Metadata());
    }

    /**
     * constructor
     *
     * @param metadata
     */
    public MetadataState(Metadata metadata) {
        this.metadata = metadata;
    }

    public Metadata getMetadata() {
        return metadata;
    }

    @Override
    public Map<String, Object> getMetadata(String section) {
        return metadata.getMetadata(section);
    }

    @Override
    public Object getMetadata(String section, String key) {
        return metadata.getMetadata(section, key);
    }

    public void setMetadata(Metadata metadata) {
        this.metadata = metadata;
    }

    @Override
    public void addMetadata(String section, Map<String, Object> value) {
        metadata.addMetadata(section, value);
        notifyMetadataAdded(section, value);
    }

    @Override
    public void addMetadata(String section, String key, Object value) {
        metadata.addMetadata(section, key, value);
        notifyMetadataAdded(section, key, value);
    }

    @Override
    public void clearMetadata(String section) {
        metadata.clearMetadata(section);
        notifyClear(section, null);
    }

    @Override
    public void clearMetadata(String section, String key) {
        metadata.clearMetadata(section, key);
        notifyClear(section, key);
    }

    /**
     * Fires the initial observable messages for all the metadata which has been added before an
     * Observer was added. This is used initially to populate the NDK with data.
     */
    public void emitObservableEvent() {
        Set<String> sections = metadata.store.keySet();

        for (String section : sections) {
            Map<String, Object> data = metadata.getMetadata(section);
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                notifyMetadataAdded(section, entry.getKey(), entry.getValue());
            }
        }
    }

    private void notifyClear(String section, String key) {
        if (key == null) {
            updateState(new StateEvent.ClearMetadataSection(section));
        } else {
            updateState(new StateEvent.ClearMetadataValue(section, key));
        }
    }

    private void notifyMetadataAdded(String section, String key, Object value) {
        if (key == null) {
            notifyClear(section, key);
        } else {
            updateState(new StateEvent.AddMetadata(section, key, metadata.getMetadata(section, key)));
        }
    }

    private void notifyMetadataAdded(String section, Map<String, Object> value) {
        for (Map.Entry<String, Object> entry : value.entrySet()) {
            updateState(new StateEvent.AddMetadata(section, entry.getKey(),
                metadata.getMetadata((String) entry.getValue())));
        }
    }

    /**
     * copy
     *
     * @param copy
     * @return MetadataState
     */
    public MetadataState copy(Metadata copy) {
        return new MetadataState(copy);
    }
}
